package io.gitee.devaper.starlight.common.config

import com.fasterxml.jackson.annotation.*
import com.fasterxml.jackson.databind.*
import com.fasterxml.jackson.datatype.jsr310.*
import com.fasterxml.jackson.datatype.jsr310.deser.*
import com.fasterxml.jackson.datatype.jsr310.ser.*
import com.fasterxml.jackson.module.kotlin.*
import io.gitee.devaper.starlight.common.constant.*
import io.gitee.devaper.starlight.common.util.*
import org.hibernate.validator.*
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.validation.*
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.servlet.config.annotation.*
import java.time.*

/**
 * WebMVC配置类
 */
@Configuration(proxyBeanMethods = false)
open class WebConfiguration : WebMvcConfigurer {


    override fun configurePathMatch(configurer: PathMatchConfigurer) {
        // 为RestController添加统一前缀, 以区分静态资源、WebSocket连接
        configurer.addPathPrefix(HTTP_URL_PREFIX) {
            it.isAnnotationPresent(RestController::class.java)
        }
    }

    /**
     * ObjectMapper Builder, SpringMVC内部会通过该组件来初始化其内部使用的ObjectMapper
     *
     * 在这里将所有需要Module及配置设置到Builder即可
     */
    @Bean
    open fun jackson2ObjectMapperBuilder(): Jackson2ObjectMapperBuilder {
        val builder = Jackson2ObjectMapperBuilder()
            .modules(
                // 添加JavaTime的支持(LocalDate、LocalTime、LocalDateTime)
                // 目前任何地方都不再使用Date类型, 尽量使用新版的API
                JavaTimeModule().apply {
                    // 设置对应的日期序列化/反序列化器, 并使用指定的format
                    addSerializer(LocalDate::class, LocalDateSerializer(localDateFormatter))
                    addDeserializer(LocalDate::class, LocalDateDeserializer(localDateFormatter))
                    addSerializer(LocalTime::class, LocalTimeSerializer(localTimeFormatter))
                    addDeserializer(LocalTime::class, LocalTimeDeserializer(localTimeFormatter))
                    addSerializer(LocalDateTime::class, LocalDateTimeSerializer(localDateTimeFormatter))
                    addDeserializer(LocalDateTime::class, LocalDateTimeDeserializer(localDateTimeFormatter))
                },
                // 添加对Kotlin的支持
                KotlinModule()
            )
            // 设置序列化时的配置, 只保留非空字段
            .serializationInclusion(JsonInclude.Include.NON_NULL)
            // 禁用unknown_properties特性
            // 该特性会导致使用constructor构造器时, 如果JSON提供的字段不足, 那么会产生异常(尽管Kotlin data class有缺省值)
            .featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
        return builder
    }

    /**
     * WebMVC Validator的自定义器
     */
    @Bean
    open fun validatorConfigurationCustomizer() = ValidationConfigurationCustomizer { configuration ->
        if (configuration is HibernateValidatorConfiguration) {
            // 开启快速失败机制
            // 正常来讲遇到第一个错误就不应该继续校验了, 默认是关闭的
            configuration.failFast(true)
        }
    }

}